﻿Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.DirectoryServices
Imports System.Runtime.Serialization
Imports System.Security.Permissions
Imports System.Security.Principal

Namespace System.Workflow.Activities
    <Serializable> _
    Public NotInheritable Class ActiveDirectoryRole
        Inherits WorkflowRole
        Implements ISerializable, IDisposable
        ' Methods
        Friend Sub New(ByVal rootEntry As DirectoryEntry, ByVal operations As ICollection([Of] IDirectoryOperation))
            If (rootEntry Is Nothing) Then
                Throw New ArgumentNullException("rootEntry")
            End If
            Me.m_root = rootEntry
            If (operations Is Nothing) Then
                Me.m_operations = New List([Of] IDirectoryOperation)
            Else
                Me.m_operations = New List([Of] IDirectoryOperation)(operations)
            End If
        End Sub

        Friend Sub New(ByVal rootEntry As DirectoryEntry, ByVal operation As IDirectoryOperation)
            If (rootEntry Is Nothing) Then
                Throw New ArgumentNullException("rootEntry")
            End If
            Me.m_root = rootEntry
            Me.m_operations = New List([Of] IDirectoryOperation)
            If (Not operation Is Nothing) Then
                Me.m_operations.Add(operation)
            End If
        End Sub

        Private Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            Me.m_name = info.GetString("m_name")
            Me.m_operations = DirectCast(info.GetValue("m_operations", GetType(List([Of] IDirectoryOperation))), List([Of] IDirectoryOperation))
            Dim path As String = info.GetString("m_root\path")
            Me.m_root = New DirectoryEntry(path)
        End Sub

        Public Function GetAllReports() As ActiveDirectoryRole
            Return New ActiveDirectoryRole(Me.RootEntry, New List([Of] IDirectoryOperation)(Me.Operations) { New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.Manager, 1) })
        End Function

        Public Function GetDirectReports() As ActiveDirectoryRole
            Return New ActiveDirectoryRole(Me.RootEntry, New List([Of] IDirectoryOperation)(Me.Operations) { New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.Manager) })
        End Function

        Public Function GetEntries() As ICollection([Of] DirectoryEntry)
            Dim list As New List([Of] DirectoryEntry) { Me.m_root }
            Dim response As New List([Of] DirectoryEntry)
            Dim i As Integer
            For i = 0 To Me.m_operations.Count - 1
                Dim k As Integer
                For k = 0 To list.Count - 1
                    Me.m_operations.Item(i).GetResult(Me.m_root, list.Item(k), response)
                Next k
                Dim list3 As List([Of] DirectoryEntry) = list
                list = response
                list3.Clear
            Next i
            Dim dictionary As New Dictionary([Of] Guid, DirectoryEntry)
            Dim j As Integer
            For j = 0 To list.Count - 1
                If Not dictionary.ContainsKey(list.Item(j).Guid) Then
                    dictionary.Add(list.Item(j).Guid, list.Item(j))
                End If
            Next j
            Return dictionary.Values
        End Function

        Public Overrides Function GetIdentities() As IList([Of] String)
            Dim list As New List([Of] String)
            Dim identifier As SecurityIdentifier
            For Each identifier In Me.GetSecurityIdentifiers
                list.Add(identifier.Translate(GetType(NTAccount)).ToString)
            Next
            Return list
        End Function

        Public Function GetManager() As ActiveDirectoryRole
            Return New ActiveDirectoryRole(Me.RootEntry, New List([Of] IDirectoryOperation)(Me.Operations) { New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.DirectReports) })
        End Function

        Public Function GetManagerialChain() As ActiveDirectoryRole
            Return New ActiveDirectoryRole(Me.RootEntry, New List([Of] IDirectoryOperation)(Me.Operations) { New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.DirectReports, 1) })
        End Function

        Public Function GetPeers() As ActiveDirectoryRole
            Dim entries As ICollection([Of] DirectoryEntry) = Me.GetEntries
            Dim operations As New List([Of] IDirectoryOperation)(Me.Operations) { New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.DirectReports), New DirectoryRedirect(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, ActiveDirectoryRoleFactory.Configuration.Manager) }
            Dim entry As DirectoryEntry
            For Each entry In entries
                operations.Add(New DirectoryLocalQuery(ActiveDirectoryRoleFactory.Configuration.DistinguishedName, CStr(entry.Properties.Item(ActiveDirectoryRoleFactory.Configuration.DistinguishedName).Item(0)), DirectoryQueryOperation.NotEqual))
            Next
            Return New ActiveDirectoryRole(Me.RootEntry, operations)
        End Function

        Public Function GetSecurityIdentifiers() As IList([Of] SecurityIdentifier)
            Dim list As New List([Of] SecurityIdentifier)
            Dim entry As DirectoryEntry
            For Each entry In Me.GetEntries
                If ((Not entry.Properties.Item("objectSid") Is Nothing) AndAlso (entry.Properties.Item("objectSid").Count <> 0)) Then
                    list.Add(New SecurityIdentifier(DirectCast(entry.Properties.Item("objectSid").Item(0), Byte()), 0))
                Else
                    WorkflowActivityTrace.Activity.TraceEvent(TraceEventType.Information, 0, "Unable to find 'objectSid' property for directory entry = {0}.", New Object() { entry.Path })
                End If
            Next
            Return list
        End Function

        Public Overrides Function IncludesIdentity(ByVal identity As String) As Boolean
            If (Not identity Is Nothing) Then
                Dim str As String
                For Each str In Me.GetIdentities
                    If (String.Compare(identity, str, StringComparison.Ordinal) = 0) Then
                        Return True
                    End If
                Next
            End If
            Return False
        End Function

        Private Sub System.IDisposable.Dispose() Implements IDisposable.Dispose
            Me.m_root.Dispose
        End Sub

        <SecurityPermission(SecurityAction.Demand, SerializationFormatter:=True)> _
        Private Sub System.Runtime.Serialization.ISerializable.GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) Implements ISerializable.GetObjectData
            info.AddValue("m_name", Me.m_name)
            info.AddValue("m_operations", Me.m_operations)
            info.AddValue("m_root\path", Me.m_root.Path)
        End Sub


        ' Properties
        Public Overrides Property Name As String
            Get
                Return Me.m_name
            End Get
            Set(ByVal value As String)
                Me.m_name = value
            End Set
        End Property

        Friend ReadOnly Property Operations As ICollection([Of] IDirectoryOperation)
            Get
                Return Me.m_operations
            End Get
        End Property

        Public ReadOnly Property RootEntry As DirectoryEntry
            Get
                Return Me.m_root
            End Get
        End Property


        ' Fields
        Private m_name As String
        Private m_operations As List([Of] IDirectoryOperation)
        Private m_root As DirectoryEntry
    End Class
End Namespace

